import axios, {AxiosRequestConfig, AxiosResponse} from 'axios'
import Cookies from 'js-cookie'
import router from '@/router'
import qs from 'qs'
import { EnumResCode } from '@/constants/EnumResCode'
import {EnumLocalStorageKeys} from '@/constants/EnumLocalStorageKey';
import { ElMessage } from 'element-plus'

// 创建一个Axios实例
const service = axios.create({
  baseURL: '/api', // 设置请求的基本URL地址
  // timeout: 5000 // 设置请求超时时间
})


//声明一个Map，用于存储每个请求的标识，和取消函数
const pending = new Map()
/**
 *添加请求
 * @param {Object} config
 * */
const addPending = (config:AxiosRequestConfig) => {
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data)
  ].join('&')
  config.cancelToken = new axios.CancelToken(cancel => {
    if (!pending.has(url)) { //如果pending 中不存在当前请求，则添加进去
      if(config!.url!.indexOf('chat/history') !=1) {
        pending.set(url, cancel)
      }

    }
  })
}

/**
 * 取消请求
 * @param {Object} config
 * */
const removePending = (config:AxiosRequestConfig) => {
  // loading.push(config)
  // console.log(loading)
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data)
  ].join('&')
  if (pending.has(url)) { //如果pending 中存在当前请求标识，需要取消当前请求，并且移除
    const cancel = pending.get(url)
    cancel(url)
    pending.delete(url)
  }
}

/**
 * 清空pending 中的请求（在路由跳转时调用）
 * */
export const clearPending = () => {
  for (const [url, cancel] of pending) {
    cancel(url)
  }
  pending.clear()
}


// 请求拦截器
service.interceptors.request.use(
  (config: AxiosRequestConfig | any) => {
    removePending(config)
    addPending(config)
    // 在请求头中添加自定义的Token等信息
    // config.headers!['token'] = Cookies.get('token') ? Cookies.get('token')! : sessionStorage.getItem('token')!
    // config.headers!['username'] = Cookies.get('userName') ? Cookies.get('userName')! : sessionStorage.getItem('userName')!;
    // config.headers!['password'] = Cookies.get('password') ? Cookies.get('password')! : sessionStorage.getItem('password')!;
    return config
  },
  error => {
    console.log(error)
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  (response:AxiosResponse) => {
    removePending(response)
    const res = response.data
    if (res.code !== EnumResCode.Success) {
      // 处理错误信息
      if(res.code === EnumResCode.NotLogin) {
        ElMessage.error('登录已过期，清重新登录')
        router.push('/loginUser')
        localStorage.removeItem(EnumLocalStorageKeys.AccessToken)
        return {
          ...res,
          isSuccess: false
        }
      }else {
        res.msg && ElMessage.error(res.msg)
        return {
          ...res,
          isSuccess: false
        }
      }
    } else {
      return {
        ...res,
        isSuccess: true
      }
    }
  },
  error => {
    if(error.name === "CanceledError") return
    return Promise.resolve({
      code:'500',
      msg: '服务器正在经历中年危机。它将在短暂的自我探索之旅后尽快回来。尝试刷新一下哦！',
      isSuccess: false
    })
  }
)
export const getToken = () => {
  return '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'
}
export const setAxios =  (url:string, method:string, params?: object | string,responseType?:string):any => {
  let axiosOption = {
    url: url,
    // transformRequest: [function (data:any) {
    //   data = JSON.stringify(data)
    //   return data
    // }],
    method: method,
    // data: params, //post 传data | get 传params
    headers: {
      // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      "Content-Type": "application/json; charset=UTF-8,Chunked: false"
    }
  }
  if (method == "post") {

    // @ts-ignore
    axiosOption.data = params;
  }else {
    // @ts-ignore
    axiosOption.params = params;
  }
  // @ts-ignore
  return service(axiosOption);
}

export const setAxiosDelete  = (url:string,params:any,isBody:boolean = true) => {
  if(isBody) {
    return service.delete(url,{
      data: params,
      headers: {
        'Content-Type': 'application/json',
        'AccessToken': getToken()
      },
    });
  }else {
    return service.delete(url,{
      params: params,
      headers: {
        'Content-Type': 'application/json',
        'AccessToken': getToken()
      },
    });
  }

}
